package com.lx.iccp.activity.app.controller;

import com.google.common.base.Preconditions;
import com.lx.iccp.activity.api.model.vo.ProcessInstanceVO;
import com.lx.iccp.activity.api.model.vo.ProcessVO;
import com.lx.iccp.activity.api.model.vo.TaskQueryParam;
import com.lx.iccp.activity.api.model.vo.TaskVO;
import com.lx.iccp.activity.app.service.ProcessImageService;
import com.lx.iccp.support.api.model.ext.UserInfo;
import com.lx.iccp.support.api.service.UserService;
import com.lx.iccp.support.common.controller.BaseController;
import com.lx.iccp.support.common.model.BaseUserInfo;
import com.lx.iccp.support.common.model.PageParam;
import com.lx.iccp.support.common.model.PagedItems;
import com.lx.iccp.support.common.model.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricVariableInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 
* @author thadYo
* @date 2021/11/12 14:28
**/
@RestController
@RequestMapping("/act/process")
@Api(tags = "工作流引擎控制类")
public class ActivitiController extends BaseController {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ProcessImageService processImageService;

    @DubboReference
    UserService userService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private TaskService taskService;

    @ApiOperation("上传一个工作流文件,部署")
    @PostMapping("/uploadWorkflow")
    public Result<Object> fileupload(@RequestParam MultipartFile uploadfile, HttpServletRequest request) {
        try {
            MultipartFile file = uploadfile;
            String filename = file.getOriginalFilename();
            InputStream is = file.getInputStream();
            String name = filename.split("\\.")[0];
            Deployment deploy = repositoryService.createDeployment()
                    .name(name).addInputStream(filename, is).deploy();
            return Result.okResponse(deploy.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.errorResponse("40001", "工作流部署失败!", "工作流部署失败!", "工作流部署失败!");
    }

    @ApiOperation("查询已部署工作流列表")
    @PostMapping("/getProcessList")
    public Result<PagedItems<ProcessVO>> getProcessList(@RequestBody PageParam pageParam) {
        int firstRow = (pageParam.getPageNum() - 1) * pageParam.getPageSize();
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().listPage(firstRow, pageParam.getPageSize());
        int total = repositoryService.createProcessDefinitionQuery().list().size();
        List<ProcessVO> processVOS = new ArrayList<>();
        for(ProcessDefinition definition : list){
            ProcessVO processVO = new ProcessVO();
            processVO.setDeploymentId(definition.getDeploymentId());
            processVO.setId(definition.getId());
            processVO.setKey(definition.getKey());
            processVO.setName(definition.getName());
            processVO.setResourceName(definition.getResourceName());
            processVO.setDiagramResourceName(definition.getDiagramResourceName());
            processVO.setDesc(definition.getDescription());
            processVOS.add(processVO);
        }
        //计算总页数
        int pages = total % pageParam.getPageSize() == 0 ? total / pageParam.getPageSize() : total /pageParam.getPageSize() + 1;
        PagedItems<ProcessVO> pagedItems = new PagedItems<>(pageParam.getPageNum(), pages,total);
        pagedItems.setItems(processVOS);
        return Result.okResponse(pagedItems);
    }


    //获取流程定义图片
    @ApiOperation(value = "根据流程定义ID获取流程定义图片", notes = "为了方便演示，使用了get请求，本质是获取到图片的流，后期可以根据需要修改。")
    @GetMapping(value = "/getProcessPicture")
    public void getImage(@RequestParam("processId") String processId, HttpServletResponse response) throws Exception{
        InputStream inputStream = null;
        try{
            inputStream = processImageService.getProcImgByProcId(processId);
            byte[] b = new byte[1024];
            int len;
            while ((len = inputStream.read(b, 0, 1024)) != -1) {
                response.getOutputStream().write(b, 0, len);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(inputStream != null){
                inputStream.close();
            }
        }
    }

    @ApiOperation("新增一个流程实例")
    @PostMapping("/addNewApply")
    public Result<Object> addNewApply(@RequestBody ProcessInstanceVO processInstanceVo){
        BaseUserInfo authUser = super.getUserInfo();
        UserInfo userInfo = userService.findUserInfoByUserId(authUser.getUserId());
        String userName = com.lx.iccp.support.common.utils.StringUtils.getUserName(userInfo.getSurname(), userInfo.getName());
        Preconditions.checkArgument(StringUtils.isNotBlank(processInstanceVo.getKey()), "请选择模板");
        HashMap<String, Object> variables=new HashMap<>();
        variables.put("username", userName);
        if(StringUtils.isNotEmpty(processInstanceVo.getTypes())){
            variables.put("types",processInstanceVo.getTypes());
        }
        if(StringUtils.isNotEmpty(processInstanceVo.getContents())){
            variables.put("contents",processInstanceVo.getContents());
        }
        Integer days = processInstanceVo.getDays();
        if(days!=null) {
            if (days <= 3){
                variables.put("user", "xiaohua");
            }
            if (days >3 && days <= 7) {
                variables.put("user", "wangls");
            }
            if (days >7 && days <= 15) {
                variables.put("user", "lizr");
            }
            variables.put("days", days);
        }
        //设置发起人
        Authentication.setAuthenticatedUserId(userInfo.getUserId());

        ProcessInstance instance = runtimeService
                .startProcessInstanceByKey(processInstanceVo.getKey(), processInstanceVo.getBusinessKey(),variables);
        return Result.okResponse(instance.getProcessInstanceId());
    }

    @ApiOperation("查询我发起的流程")
    @PostMapping("/myApplyList")
    public Result<PagedItems<ProcessInstanceVO>> myApplyList(@RequestBody PageParam pageParam) {
        BaseUserInfo userInfo = super.getUserInfo();
        //创建查询对象,查询该用户发起的流程
        int firstRow = (pageParam.getPageNum() - 1) * pageParam.getPageSize();
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery()
                .startedBy(userInfo.getUserId())
                .listPage(firstRow, pageParam.getPageSize());
        long count = historyService.createHistoricProcessInstanceQuery()
                .startedBy(userInfo.getUserId())
                .count();
        List<ProcessInstanceVO> instanceVos = new ArrayList<>();
        for(HistoricProcessInstance instance : list){
            ProcessInstanceVO instanceVo = new ProcessInstanceVO();
            instanceVo.setProcessInstanceName(instance.getStartUserId()+"_" + instance.getProcessDefinitionName());
            instanceVo.setStartTime(instance.getStartTime());
            instanceVo.setInstanceId(instance.getId());
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(instance.getId())
                    .singleResult();
            if(processInstance==null){
                instanceVo.setInstanceStatus("已完成");
            }else{
                instanceVo.setInstanceStatus("执行中");
            }
            instanceVos.add(instanceVo);
        }
        //计算总页数
        int total = (int) count;
        int pages = total % pageParam.getPageSize() == 0 ? total / pageParam.getPageSize() : total /pageParam.getPageSize() + 1;
        PagedItems<ProcessInstanceVO> pagedItems = new PagedItems<>(pageParam.getPageNum(), pages,total);
        pagedItems.setItems(instanceVos);
        return Result.okResponse(pagedItems);
    }

    @ApiOperation(value = "查询我的代办任务", notes = "指定了几个用户。老师 wangls, 主任 lizr， 校长 admin， 班长 xiaohua")
    @PostMapping("/myWaitingToDo")
    public Result<PagedItems<TaskVO>> myWaitingToDo(@RequestBody TaskQueryParam taskQueryParam){

        int firstRow = (taskQueryParam.getPageNum() - 1) * taskQueryParam.getPageSize();
        List<Task> taskList = taskService.createTaskQuery()
                .taskAssignee(taskQueryParam.getUserId())
                .listPage(firstRow, taskQueryParam.getPageSize());
        long count = taskService.createTaskQuery()
                .taskAssignee(taskQueryParam.getUserId()).count();
        List<TaskVO> list = new ArrayList<>();
        for(Task t : taskList){
            TaskVO taskVO = new TaskVO();
            String username = "";
            Object variable = taskService.getVariable(t.getId(), "username");
            username = (String) variable;
            taskVO.setDesc(username +"-请假申请单");
            taskVO.setCreateTime(t.getCreateTime());
            taskVO.setName(t.getName());
            taskVO.setExecutionId(t.getExecutionId());
            taskVO.setTaskStatus(t.getDelegationState() == null ? "" : t.getDelegationState().toString());
            taskVO.setId(t.getId());
            list.add(taskVO);
        }
        int total = (int) count;
        int pages = total % taskQueryParam.getPageSize() == 0 ? total / taskQueryParam.getPageSize() : total /taskQueryParam.getPageSize() + 1;
        PagedItems<TaskVO> pagedItems = new PagedItems<>(taskQueryParam.getPageNum(), pages,total);
        pagedItems.setItems(list);
        return Result.okResponse(pagedItems);
    }

    @ApiOperation(value = "通过当前任务", notes = "msg: yes 通过； msg: no 驳回")
    @PostMapping("/approval")
    public Result<Object> approvalPass(@RequestBody TaskVO taskVO){
        taskService.setVariable(taskVO.getId(),"msg",taskVO.getMsg());
        taskService.complete(taskVO.getId());
        return Result.okResponse("审批完成");
    }

    //获取流程定义图片
    @ApiOperation(value = "获取流程实例图片", notes = "为了方便演示，使用了get请求，本质是获取到图片的流，后期可以根据需要修改。")
    @GetMapping(value = "/getInstancePicture")
    public void getInstancePicture(@RequestParam("instanceId") String instanceId, HttpServletResponse response) throws Exception{
        InputStream inputStream = null;
        try{
            inputStream = processImageService.getImgByInstanceId(instanceId);
            byte[] b = new byte[1024];
            int len;
            while ((len = inputStream.read(b, 0, 1024)) != -1) {
                response.getOutputStream().write(b, 0, len);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(inputStream != null){
                inputStream.close();
            }
        }
    }

    @ApiOperation(value = "查询我参与审批的流程实例")
    @PostMapping("/hisWork")
    public Result<PagedItems<ProcessInstanceVO>> hisWork(@RequestBody TaskQueryParam taskQueryParam){
        int firstRow = (taskQueryParam.getPageNum() - 1) * taskQueryParam.getPageSize();
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(taskQueryParam.getUserId())
                .listPage(firstRow, taskQueryParam.getPageSize());

        long count = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(taskQueryParam.getUserId())
                .count();

        List<ProcessInstanceVO> instanceVos = new ArrayList<>();
        historicTaskInstances.forEach(s->{
            HistoricProcessInstance his = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(s.getProcessInstanceId()).singleResult();
            ProcessInstanceVO instanceVo = new ProcessInstanceVO();
            instanceVo.setProcessInstanceName(his.getStartUserId()+"_" + his.getProcessDefinitionName());
            instanceVo.setStartTime(his.getStartTime());
            instanceVo.setInstanceId(his.getId());
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(his.getId())
                    .singleResult();
            if(processInstance==null){
                instanceVo.setInstanceStatus("已完成");
            }else{
                instanceVo.setInstanceStatus("执行中");
            }
            instanceVos.add(instanceVo);
        });
        int total = (int) count;
        int pages = total % taskQueryParam.getPageSize() == 0 ? total / taskQueryParam.getPageSize() : total /taskQueryParam.getPageSize() + 1;
        PagedItems<ProcessInstanceVO> pagedItems = new PagedItems<>(taskQueryParam.getPageNum(), pages,total);
        pagedItems.setItems(instanceVos);
        return Result.okResponse(pagedItems);
    }

    //获取流程定义图片
    @ApiOperation(value = "获取我审批的节点图片", notes = "为了方便演示，使用了get请求，本质是获取到图片的流，后期可以根据需要修改。")
    @GetMapping(value = "/getImgByMyPassed")
    public void getImgByMyPassed(@RequestParam("instanceId") String instanceId, @RequestParam("userId") String userId, HttpServletResponse response) throws Exception{
        InputStream inputStream = null;
        try{
            inputStream = processImageService.getImgByMyPassed(instanceId, userId);
            byte[] b = new byte[1024];
            int len;
            while ((len = inputStream.read(b, 0, 1024)) != -1) {
                response.getOutputStream().write(b, 0, len);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(inputStream != null){
                inputStream.close();
            }
        }
    }
}
